#ifndef SYMBOLTABLE_HPP_INCLUDED
#define SYMBOLTABLE_HPP_INCLUDED

#define STD_LEXEME_LENGTH 10000
#define PRIME_NUMBER 349

/*
 * Constantes que referenciam as classes especializadas de IDSymbol. Desta forma evita-se o uso de dynamic_cast.
 */
#define CLASS_SYMBOL 0
#define VARIABLE_SYMBOL 1
#define METHOD_SYMBOL 2
#define PARAMETER_SYMBOL 3
#define ATTRIBUTE_SYMBOL 4

class ClassSymbol;
class MethodSymbol;

/********************************************************************
*         Class BasicSymbol :: classe generica de simbolos          *
********************************************************************/
class BasicSymbol{
public:
    unsigned short int lexemeIdx;
    BasicSymbol *next;
public:
    BasicSymbol(unsigned short int, BasicSymbol*);
    unsigned short int getLexemeIdx();
    BasicSymbol* getNext();
    ~BasicSymbol();
};

/********************************************************************
*                Class IDSymbol :: classe de IDs                    *
********************************************************************/
class IDSymbol : public BasicSymbol {
public:
    unsigned int symbolType;
public:
    IDSymbol(unsigned short int, IDSymbol*, unsigned int);
};

/********************************************************************
*           Class Type :: mapeia tipos primitivos ou não            *
********************************************************************/
class Type{
public:
    char *Class;
    unsigned short int primitiveType;
    int arrayLimit;
public:
    Type(char*, unsigned short int, int);
    ~Type();
};

/*********************************************************************
*Class VariableSymbol :: mapeia declaração de variáveis ou instâncias*
*********************************************************************/
class VariableSymbol : public IDSymbol {
public:
    Type *type;
    unsigned short int scope;
    bool active;
    bool defined;
    VariableSymbol *nextVariable;
public:
    VariableSymbol(unsigned short int, IDSymbol*, Type*, unsigned int, unsigned short int, bool, VariableSymbol*);
    ~VariableSymbol();
};

/********************************************************************
*     Class VariableSymbolList :: encadeia variáveis para o visitor *
********************************************************************/
class VariableSymbolList{
public:
    VariableSymbol *thisVar;
    VariableSymbolList *nextVar;
public:
    VariableSymbolList(VariableSymbol *thisVar, VariableSymbolList *nextVar);
    ~VariableSymbolList();
};

/********************************************************************
*       Class AtributeSymbol :: mapeia declaração de atributos      *
********************************************************************/
class AttributeSymbol : public IDSymbol {
public:
    VariableSymbol *attribute;
    AttributeSymbol *nextAttribute;
    ClassSymbol *owner;
public:
    AttributeSymbol(unsigned short int, IDSymbol*, unsigned int, VariableSymbol*, AttributeSymbol*);
    ~AttributeSymbol();
};

/********************************************************************
*Class ParameterSymbol :: mapeia declaração de parâmetros de funções*
********************************************************************/
class ParameterSymbol : public IDSymbol {
public:
    VariableSymbol *param;
    ParameterSymbol *nextParam;
    MethodSymbol *owner;
public:
    ParameterSymbol(unsigned short int, IDSymbol*, unsigned int, VariableSymbol*, ParameterSymbol*);
    ~ParameterSymbol();
};

/********************************************************************
*        Class MethodSymbol :: mapeia declaração de métodos         *
********************************************************************/
class MethodSymbol : public IDSymbol {
public:
    ParameterSymbol *firstParam;
    VariableSymbol *firstVariable;
    Type *returnType;
    ClassSymbol *owner;
    MethodSymbol *nextMethod;
public:
    MethodSymbol(unsigned short int, IDSymbol*, unsigned int, ParameterSymbol*, VariableSymbol*, Type*, MethodSymbol*);
    ~MethodSymbol();
};

/********************************************************************
*        Class ClassSymbol :: mapeia declaração de classes          *
********************************************************************/
class ClassSymbol : public IDSymbol {
public:
    ClassSymbol *extendedClass;
    MethodSymbol *firstMethod;
    AttributeSymbol *firstAttribute;
public:
    ClassSymbol(unsigned short int, IDSymbol*, unsigned int, ClassSymbol*, MethodSymbol*,AttributeSymbol*);
    ~ClassSymbol();
};

/********************************************************************
*           Class LiteralSymbol :: classe de Literais               *
********************************************************************/
class LiteralSymbol : public BasicSymbol {
public:
    LiteralSymbol(unsigned short int, LiteralSymbol*);
};

/********************************************************************
*     Class ReservedWordSymbol :: classe de Palavras Reservadas     *
********************************************************************/
class ReservedWordSymbol : public BasicSymbol{
public:
    unsigned short int token;
public:
    ReservedWordSymbol(unsigned short int idx, ReservedWordSymbol *Next, unsigned short int Token);
    unsigned short int getToken();
};

/********************************************************************
*         Class BasicSymbolTable :: classe da Tabela de Simbolos    *
********************************************************************/
class BasicSymbolTable {
public:
    char* lexemes;
    unsigned int lexemesLength;
    unsigned int position; //This attribute references the first free position in 'lexemes'
public:
    BasicSymbolTable();
    int hash(char *key);
    void addSymbol(char* lex);
    virtual void printTable() = 0;
};

/********************************************************************
*                      Class IDSymbolTable                          *
********************************************************************/
class IDSymbolTable : public BasicSymbolTable{
public:
    IDSymbol* table[PRIME_NUMBER];
public:
    IDSymbolTable();
    ~IDSymbolTable();
    IDSymbol* searchID(char*, unsigned int);
    void addSymbol(IDSymbol*, char*);
    void printTable();
};

/********************************************************************
*                   Class LiteralSymbolTable                        *
********************************************************************/
class LiteralSymbolTable : private BasicSymbolTable{
private:
    LiteralSymbol* table[PRIME_NUMBER];
public:
    LiteralSymbolTable();
    ~LiteralSymbolTable();
    void addSymbol(char* lex);
    void printTable();
};

/********************************************************************
*                   Class ReservedWordSymbolTable                   *
********************************************************************/
class ReservedWordSymbolTable : private BasicSymbolTable{
private:
    ReservedWordSymbol* table[PRIME_NUMBER];
public:
    ReservedWordSymbolTable();
    ~ReservedWordSymbolTable();
    void addSymbol(char* lex, unsigned short int token);
    unsigned int searchReservedWord(char *lex);
    void printTable();
};

void printTables();

#endif // SYMBOLTABLE_HPP_INCLUDED
